// read_file is  读取日志
extern crate ansi_term;
use ansi_term::Colour;
use std::fs::File;
//use std::io::prelude::*;
use std::io::{BufRead, BufReader};
// use std::fs::File;
extern crate clap;
extern crate libc;
use clap::{App, SubCommand};

#[allow(dead_code)]
fn gen_value<T>(_: &T)  {
    println!("类型： {}\n", std::any::type_name::<T>());
    Default::default()
}

/// 查询的关键词高亮显示
fn color_log(s: String, kyw: String) -> () {
    let line = s;
    use ansi_term::Colour::{Blue, Yellow};
    use ansi_term::Style;
    let l = kyw.len();
    match line.find(&kyw) {
        Some(start_bytes) => {
            let result = &line[start_bytes..start_bytes + l];
            print!("{}", &line[..start_bytes]);
            print!("{}", Style::new().on(Blue).fg(Yellow).paint(result));
            let subline = &line[start_bytes + l..];
            color_log(subline.to_string(), kyw.to_string());
        }
        None => {
            println!("{}", line);
        }
    }
}
fn read_file(filename: String, kyw: String, begin: i32, end: i32) -> std::io::Result<()> {
    //let file = File::open(filename).unwrap();
    //let f = BufReader::new(file);

use encodingbufreader::{BufReaderEncoding};
use encoding::all::{UTF_8};
let file = File::open(filename)?;
let mut i = 1;
// println!("开始:{}\t;结束:{}\n",begin,end);
for line in BufReaderEncoding::new(file, UTF_8)
	.lines(){
        if (begin == 0 && end == 0)||(  i >= begin && i <= end ) {
            let s = format!("{:08}", i);
            print!("{}", Colour::Yellow.paint(s));
            if kyw.len() == 0 {
            println!("{}",line?);
            }else{
                color_log(line?, kyw.to_string());
            }

        }
        i=i+1;
        if i>end && end!=0{
            break;
        }
    }
    Ok(())
}

#[allow(dead_code)]
// Returns the path to the user's template directory.
//这个方法只能用于string类型，容易出现【stream did not contain valid UTF-8】
//works, but it keeps allocation a string for each line. Besides, if there is no line break on the input file, the whole file would be load to the memory.
fn read_file_old(filename: String, kyw: String, begin: i32, end: i32) -> std::io::Result<()> {
    let file = File::open(filename).unwrap();
    let fin = BufReader::new(file);
    let mut i = 1;
    for line in fin.lines() {
        if begin == 0 && end == 0 {
            let s = format!("{:07}", i);
            print!("{}", Colour::Yellow.paint(s));
            if kyw.len() == 0 {
                gen_value(&line);
                println!(" {}", line.unwrap().to_string());
            } else {
                color_log(line.unwrap().to_string(), kyw.to_string());
            }
        } else {
            if i >= begin && i <= end {
                let s = format!("{:07}", i);
                print!("{}", Colour::Yellow.paint(s));
                if kyw.len() == 0 {
                    println!(" {}", line.unwrap().to_string());
                } else {
                    color_log(line.unwrap().to_string(), kyw.to_string());
                }
            }
        }
        i = i + 1;
    }
    Ok(())
}


/// flag用于参数
fn flag() -> () {
    let matches = App::new("Sunnycat")
        .version("1.5")
        .author("Sunny Region. <jinheking@gmail.com>")
        .about(
            "日志检索，增强版cat.
        例子:sunnycat --keyword example --file log.txt
                 ./sunnycat lines -r 5,10
        ",
        )
        .args_from_usage("-k, --keyword=[KEYWORD] '搜索关键字'")
        .args_from_usage("-f ,--file=[FILE] 'Sets the input file to use'")
        .subcommand(
            SubCommand::with_name("lines")
                .about("选择哪些行显示")
                .version("1.5")
                .author("Sunny Region. <jinheking@gmail.com>")
                .args_from_usage(
                    "-r --rows '输入行数，例如：-r 1,10,表示从第一行到第10行。'
                                    [LINES]  ' 1,10,表示从第一行到第10行。'",
                ),
        )
        .get_matches();

    let filename = matches.value_of("file").unwrap_or("log.txt");
    let key = matches.value_of("keyword").unwrap_or("");
    let mut lines: String = "0,0".to_string();
    if let Some(matches) = matches.subcommand_matches("lines") {
        if matches.is_present("rows") {
            lines = matches.value_of("LINES").unwrap_or("0,0").to_string();
        } else {
            println!("Printing normally...");
        }
    }
    let l: Vec<&str> = lines.split(",").collect();
    let begin: i32 = l[0].parse().unwrap();
    let end: i32 = l[1].parse().unwrap();
    let _f = match File::open(filename) {
        Ok(_) => {
            let _r = read_file(filename.to_string(), key.to_string(), begin, end);
        }
        Err(_why) => {
            println!("文件({ })打开失败.", filename);
        }
    };
}

/// 主程序
fn main() {
    unsafe {
        libc::signal(libc::SIGPIPE, libc::SIG_DFL);
    }
    flag();
}
